﻿using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using Microsoft.TeamFoundation.WorkItemTracking.Client;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TypeMock.ArrangeActAssert;
using WorkItemAnalyser.Core.Assertions;

namespace WICSA.Test.AssertionTests
{
    [TestClass]
    public class LinkAssertionTests
    {
        #region Exacts

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnInvalidOnAssertExactWithNoLinks()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 1, "UnknownLinkType", true);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(0);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsFalse(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnInvalidOnAssertExactWithNegativeLinkCount()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", -1, "UnknownLinkType", true);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(2);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsFalse(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnValidOnAssertSpecificLinkTypeExactWithCorrectCount()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 2, "UnknownLinkType", true);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(2);
            Isolate.WhenCalled(
                () =>
                workItem.WorkItemLinks.OfType<WorkItemLink>().Count(
                    workItemLink => workItemLink.ArtifactLinkType.Name == "Bug")).WillReturn(2);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsTrue(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnInvalidOnAssertExactWithMoreLinks()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 2, "UnknownLinkType", true);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(4);
            Isolate.WhenCalled(
                () =>
                workItem.WorkItemLinks.OfType<WorkItemLink>().Count(
                    workItemLink => workItemLink.ArtifactLinkType.Name == "Bug")).WillReturn(4);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsFalse(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnInvalidOnAssertExactWithLessTotalLinks()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 2, "UnknownLinkType", true);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(1);
            Isolate.WhenCalled(
                () =>
                workItem.WorkItemLinks.OfType<WorkItemLink>().Count(
                    workItemLink => workItemLink.ArtifactLinkType.Name == "Bug")).WillReturn(1);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsFalse(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnInvalidOnAssertExactWithLessSpecificLinks()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 2, "UnknownLinkType", true);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(4);
            Isolate.WhenCalled(
                () =>
                workItem.WorkItemLinks.OfType<WorkItemLink>().Count(
                    workItemLink => workItemLink.ArtifactLinkType.Name == "Bug")).WillReturn(1);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsFalse(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        #endregion

        #region NonExacts

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnValidOnAssertNonExactWithMoreLinksThanRequired()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 2, "UnknownLinkType", false);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(3);
            Isolate.WhenCalled(
                () =>
                workItem.WorkItemLinks.OfType<WorkItemLink>().Count(
                    workItemLink => workItemLink.ArtifactLinkType.Name == "Bug")).WillReturn(3);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsTrue(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnValidOnAssertNonExactWithCorrectCountOfLinks()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 2, "UnknownLinkType", false);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(2);
            Isolate.WhenCalled(
                () =>
                workItem.WorkItemLinks.OfType<WorkItemLink>().Count(
                    workItemLink => workItemLink.ArtifactLinkType.Name == "Bug")).WillReturn(2);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsTrue(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnInvalidOnAssertNonExactWithLessTotalLinksThanRequired()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 2, "UnknownLinkType", false);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(1);
            Isolate.WhenCalled(
                () =>
                workItem.WorkItemLinks.OfType<WorkItemLink>().Count(
                    workItemLink => workItemLink.ArtifactLinkType.Name == "Bug")).WillReturn(1);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsFalse(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        [Isolated]
        [TestMethod]
        public void LinkAssertion_Execute_ShouldReturnInvalidOnAssertNonExactWithLessSpecificLinksThanRequired()
        {
            //Arrange
            var workItems = new Collection<WorkItem>();
            var workItem = Isolate.Fake.Instance<WorkItem>();
            var assertion = new LinkAssertion("Bug", 2, "UnknownLinkType", false);

            Isolate.WhenCalled(() => workItem.Links.Count).WillReturn(3);
            Isolate.WhenCalled(
                () =>
                workItem.WorkItemLinks.OfType<WorkItemLink>().Count(
                    workItemLink => workItemLink.ArtifactLinkType.Name == "Bug")).WillReturn(1);
            workItems.Add(workItem);

            //Act           
            var results = assertion.Execute(workItems);

            //Assert
            Assert.IsTrue(results.Count() == 1);
            Assert.IsFalse(results.ElementAt(0).IsValid);
            Debug.WriteLine(results.ElementAt(0).Message);
        }

        #endregion
    }
}